﻿package net.fishbowlmedia.scroller3d.control 
{
	import net.fishbowlmedia.scroller3d.model.MoviePlaneModel;
	
	import com.caurina.transitions.Tweener;
	
	import org.papervision3d.materials.MovieMaterial;
	import org.papervision3d.objects.primitives.Plane;
	
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	
	/**
	* ...
	* @author Tom Lauck
	*/
	public class VanishingCoverControl extends MoviePlaneControl
	{
		private var _tweenTransition:String;
		private var _startingCoverId:int;
		private var _selectedCoverAngle:Number;
		private var _selectedCoverOffest:int;
		private var _selectedCoverScale:Number;
		private var _coverAngle:Number;	
		private var _tweenTime:Number;
		private var _visibleCoverLimit:int;
		private var _previousSelectedMoviePlane:MoviePlaneModel;
		private var _vanishingPointDirection:String = "ASC";
		public var moviePlanesPlaneId:Array;
		
		public function VanishingCoverControl() 
		{
			moviePlanesPlaneId = new Array();
			selectedPlaneId = 1;
			addEventListener("PlaneClick", onPlaneClick);
		}
		public function addPlaneToScene(id:int, targetMovie:MovieClip):void
		{
			moviePlanes[id] = createMoviePlane(id, targetMovie);
			
			if (id == selectedPlaneId)
				selectedMoviePlane = moviePlanes[id];
			
			previousSelectedMoviePlane = selectedMoviePlane;
			
			scene.addChild(moviePlanes[id].plane);
			moviePlanesPlaneId[id] = moviePlanes[id];
			tweenPlaneById(id);			
		}
		public function tweenPlaneById(id:int):void
		{	
			var plane:Plane = moviePlanes[id].plane as Plane;	
			var movieMaterial:MovieMaterial = plane.material as MovieMaterial;
			var movie:MovieClip = movieMaterial.movie as MovieClip;
			
			var movieAlpha = 1;
			var planeX:Number = (startingCoverId-id + 1) * -seperation - offset;
			var planeScale:Number = 1;
			var planeRotationY:Number = -coverAngle;
			var planeTweenTime = tweenTime;
			var planeZ:Number = 0;
			
			switch(vanishingPointDirection)
			{
				case "ASC":
					movieAlpha = (1 - (1 / ((visibleCoverLimit * 1.5) - id)));
					if (movieAlpha > 1) movieAlpha = 1;
					break;
				case "CENTER":
					if (id < selectedPlaneId)
					{
						planeZ = ((selectedPlaneId - id) * 100);
					}					
					else if (id > selectedPlaneId && id < (totalPlanes - visibleCoverLimit))
					{
						planeZ = ((id - selectedPlaneId) * 100);
					}
					else if (id >= (totalPlanes - visibleCoverLimit))
					{
						planeZ = ((visibleCoverLimit - selectedPlaneId + (totalPlanes - id)) * 100);						
					}
					break;
			}
			
			if (id == selectedPlaneId)
			{
				if (selectedMoviePlane.planeId != previousSelectedMoviePlane.planeId)
				{
					dispatchEvent(new Event("CoverSelected", true));
					previousSelectedMoviePlane = selectedMoviePlane;
				}
				
				planeX = planeX + selectedCoverOffest;
				planeScale = planeScale + selectedCoverScale;
				planeRotationY = selectedCoverAngle;
				movieAlpha = 1;
			}
			else if (id >= 0 && id <= visibleCoverLimit)
			{
				movieMaterial.smooth = true;
				movieMaterial.interactive = true;
				movieMaterial.animated = true;
			}
			else
			{				
				movieMaterial.smooth = false;
				movieMaterial.interactive = false;
				movieMaterial.animated = false;
			}
			
			if (id >= (totalPlanes - visibleCoverLimit))
			{			
				for (var i:int = 1; i <= visibleCoverLimit; i ++)
				{
					if (id == (totalPlanes - i))
					{
						planeX = (startingCoverId - ( -i) + 1) * -seperation - offset;
					}
				}			
			}
			
			Tweener.addTween
			(
				movie,
				{
					alpha:movieAlpha,
					time:planeTweenTime,
					transition:tweenTransition 
				}
			);
			
			Tweener.addTween
			(
				plane, 
				{
					x: planeX,
					z: planeZ,
					scale:planeScale,
					rotationY: planeRotationY,
					time:planeTweenTime,
					transition:tweenTransition,
					onComplete:function()
					{
						if (id == totalPlanes - 1)
						{
							keyboardCache = 0;
							mouseWheelCache = 0;
						}
					}
				}
			);
			
		}
		private function loopPlaneTween():void
		{
			for(var i:int = 0; i < totalPlanes; i++)
			{
				tweenPlaneById(i);
			}
		}
		public function scrollRight():void
		{
			var coversView:Array = moviePlanes;
			var nextCover:MoviePlaneModel = coversView[selectedPlaneId + 1] as MoviePlaneModel;
			var nextCoverId:int = moviePlanesPlaneId.indexOf(nextCover);
			planeClickId = nextCoverId;
			scrollPaneById(planeClickId);
		}
		private function shiftArrayRight():void
		{
			moviePlanes.unshift(moviePlanes.pop());			
			for (var i:int = 1; i <= visibleCoverLimit; i ++)
			{
				moviePlanes[totalPlanes - i].plane.x = (startingCoverId-(-i) + 1) * -seperation - offset;
			}
			loopPlaneTween();
		}
		public function scrollLeft():void
		{
			var coversView:Array = moviePlanes;
			var nextCover:MoviePlaneModel = coversView[selectedPlaneId - 1] as MoviePlaneModel;
			var nextCoverId:int = moviePlanesPlaneId.indexOf(nextCover);
			planeClickId = nextCoverId;
			scrollPaneById(planeClickId);
		}
		private function shiftArrayLeft():void
		{			
			moviePlanes.push(moviePlanes.shift());
			moviePlanes[totalPlanes - (visibleCoverLimit + 1)].plane.x = (startingCoverId - (totalPlanes - (visibleCoverLimit) + 1) + 1) * -seperation - offset;
			loopPlaneTween();
		}
		public function scrollPaneById(id:int):void
		{
			var cover:MoviePlaneModel = moviePlanesPlaneId[id] as MoviePlaneModel;
			
			selectedMoviePlane = cover;
			
			var dynamicId:int = moviePlanes.indexOf(cover);
			if ( dynamicId > selectedPlaneId )
			{
				for (var a:int = selectedPlaneId; a < dynamicId; a ++)
				{
					shiftArrayLeft();
				}
			}
			
			else if ( dynamicId < selectedPlaneId )
			{
				for (var b:int =  dynamicId; b < selectedPlaneId; b ++)
				{					
					shiftArrayRight();
				}
			}
		}
		private function onPlaneClick(e:Event):void
		{
			scrollPaneById(planeClickId);
		}
		
		private var keyboardCache:int = visibleCoverLimit;
		public function onKeyDown(e:KeyboardEvent) {			
			if (keyboardCache <= startingCoverId)
			{
				switch (e.keyCode) {
					case Keyboard.LEFT:
						scrollRight();
						break;
					case Keyboard.RIGHT:
						scrollLeft();
						break;
					case Keyboard.UP:
					case Keyboard.PAGE_UP:
						scrollLeft();
						break;					
					case Keyboard.DOWN:					
					case Keyboard.PAGE_DOWN:
						scrollRight();
						break;		
				}
				keyboardCache ++;
			}
		}		
		private var mouseWheelCache:int = visibleCoverLimit;
		public function onMouseWheel(e:MouseEvent):void
		{
			if (e.delta < 0) 
				scrollRight();
			else 
				scrollLeft();
		}		
		//getters/setters
		public function get tweenTransition():String { return _tweenTransition; }
		
		public function set tweenTransition(value:String):void 
		{
			_tweenTransition = value;
		}
		
		public function get startingCoverId():int { return _startingCoverId; }
		
		public function set startingCoverId(value:int):void 
		{
			_startingCoverId = value;
		}
		
		public function get selectedCoverAngle():Number { return _selectedCoverAngle; }
		
		public function set selectedCoverAngle(value:Number):void 
		{
			_selectedCoverAngle = value;
		}
		
		public function get selectedCoverOffest():int { return _selectedCoverOffest; }
		
		public function set selectedCoverOffest(value:int):void 
		{
			_selectedCoverOffest = value;
		}
		
		public function get selectedCoverScale():Number { return _selectedCoverScale; }
		
		public function set selectedCoverScale(value:Number):void 
		{
			_selectedCoverScale = value;
		}
		
		public function get coverAngle():Number { return _coverAngle; }
		
		public function set coverAngle(value:Number):void 
		{
			_coverAngle = value;
		}
		
		public function get tweenTime():Number { return _tweenTime; }
		
		public function set tweenTime(value:Number):void 
		{
			_tweenTime = value;
		}
		
		public function get visibleCoverLimit():int { return _visibleCoverLimit; }
		
		public function set visibleCoverLimit(value:int):void 
		{
			_visibleCoverLimit = value;
		}
		
		public function get previousSelectedMoviePlane():MoviePlaneModel { return _previousSelectedMoviePlane; }
		
		public function set previousSelectedMoviePlane(value:MoviePlaneModel):void 
		{
			_previousSelectedMoviePlane = value;
		}
		
		public function get vanishingPointDirection():String { return _vanishingPointDirection; }
		
		public function set vanishingPointDirection(value:String):void 
		{
			_vanishingPointDirection = value;
		}
	}
	
}